package src.origintrail;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Scanner;

import java.util.logging.Level;
import java.util.logging.Logger;
import src.origintrail.Player.Pace;

/**
 * Class representing a Map in OriginTrail
 * @author cassidy
 */
//oxen
public class Map implements List<MapNode> {

    private LinkedList<MapNode> list;
    private int location;
    private int distanceTraveled;
    private int distanceToNext;
    private boolean one;
    public static boolean stop;

    /**
     * Constructor that creates an instance of map generated from a file
     * @param file
     */
    public Map(String file) {
        MapNode temp;
        list = new LinkedList<MapNode>();
        try {
            File mapfile = new File(file);
            Scanner scan = new Scanner(mapfile);
            while (scan.hasNext()) {
                temp = new MapNode(scan.next(), scan.nextInt(), scan.nextInt(), scan.nextInt());
                list.add(temp);
            }


        } catch (FileNotFoundException e) {
            System.out.println("you're doing it wrong -_-' (map file not found)");

        }
        location = 0;
        distanceTraveled = 0;
        one = true;

        distanceToNext = list.get(location).getDistanceToNext();

    }

    /**
     * A method that moves a player forward one complete node, or location on the map
     * at a speed that is dependant on pace. Rations are reduced based on distance
     * traveled and pace.
     */
    public void move() {
        one = false;
        stop = false;
        if (!(OriginTrail.plr.getWagonSpeed().equals(Pace.STOP))) {
            while ((list.get(location).getDistanceToNext() != 0) && !stop) {
                moveOne();
            }
        }
        /*		else
        {
        int temp = list.get(location).getDistanceToNext();
        while(temp > 0)
        {
        moveOne();
        temp--;
        }
        }
         *///...why is this here o.O
        location++;
        distanceToNext = list.get(location).getDistanceToNext();
        one = true;
    }

    /**
     * Method that moves the player forward one "unit" based on current pace
     * the food and distance are updated accordingly
     */
    //change amount of movement based on oxen
    public void moveOne() {
        Item nom = new Food().initialize(0);
        Item bigNom = new Oxen().initialize(0);
        int amountfood = OriginTrail.plr.bags.find(nom).getStack();
        int oxen = OriginTrail.plr.bags.find(bigNom).getStack();
        Pace tempPace = OriginTrail.plr.getWagonSpeed();
        if (oxen == 0) {
            OriginTrail.plr.setWagonSpeed(Pace.SLOW);
        }
        oxen = oxen + 2;
        if ((OriginTrail.plr.getFoodSpeed().compareTo(Player.Rations.STARVING) > (OriginTrail.plr.bags.find(nom).getStack()))) {
            OriginTrail.plr.bags.find(nom).setStack(0);
        } else {
            OriginTrail.plr.bags.find(nom).setStack(((OriginTrail.plr.bags.find(nom).getStack())
                    - ((OriginTrail.plr.getFoodSpeed().compareTo(Player.Rations.STARVING)) * (OriginTrail.plr.getParty().length + 1))));
            ((Wagon) OriginTrail.plr.bags.find(new Wagon())).addMassHeld(
                    ((-2 * ((OriginTrail.plr.getFoodSpeed().compareTo(Player.Rations.STARVING))
                    * (OriginTrail.plr.getParty().length + 1))) / OriginTrail.plr.getWagonSpeed().compareTo(Player.Pace.STOP)));
        }

        if (((OriginTrail.plr.getWagonSpeed().compareTo(Player.Pace.STOP)) * oxen) > list.get(location).getDistanceToNext()) {
            int temp = (((OriginTrail.plr.getWagonSpeed().compareTo(Player.Pace.STOP)) * oxen) - list.get(location).getDistanceToNext());
            if (amountfood > OriginTrail.plr.bags.find(nom).getStack()
                    + ((temp * ((OriginTrail.plr.getFoodSpeed().compareTo(Player.Rations.STARVING)) * (OriginTrail.plr.getParty().length + 1))) / (OriginTrail.plr.getWagonSpeed().compareTo(Player.Pace.STOP)))) {
                OriginTrail.plr.bags.find(nom).setStack(OriginTrail.plr.bags.find(nom).getStack()
                        + ((temp * ((OriginTrail.plr.getFoodSpeed().compareTo(Player.Rations.STARVING)) * (OriginTrail.plr.getParty().length + 1))) / (OriginTrail.plr.getWagonSpeed().compareTo(Player.Pace.STOP))));
                ((Wagon) OriginTrail.plr.bags.find(new Wagon())).addMassHeld(
                        ((temp * ((OriginTrail.plr.getFoodSpeed().compareTo(Player.Rations.STARVING))
                        * (OriginTrail.plr.getParty().length + 1))) / (OriginTrail.plr.getWagonSpeed().compareTo(Player.Pace.STOP) * oxen)));
            }

            distanceTraveled += list.get(location).getDistanceToNext();
        } else {
            distanceTraveled += (OriginTrail.plr.getWagonSpeed().compareTo(Player.Pace.STOP) * oxen);
        }
        list.get(location).setDistanceToNext(list.get(location).getDistanceToNext() - ((OriginTrail.plr.getWagonSpeed().compareTo(Player.Pace.STOP)) * oxen));
        if (list.get(location).getDistanceToNext() < 0) {
            list.get(location).setDistanceToNext(0);
        }
        if ((list.get(location).getDistanceToNext() == 0) && one) {
            location++;
        }
        if (OriginTrail.plr.bags.find(nom).getStack() <= 0) {
            OriginTrail.plr.bags.find(nom).setStack(0);
            OriginTrail.plr.setHealth((int) (Math.floor(OriginTrail.plr.getHealth() * .8)));
            //OriginTrail.plr.setWagonSpeed(Pace.STOP);
        }
        if (distanceToNext == 0 && !list.get(location).isEnd()) {
            int i = location + 1;
            distanceToNext = list.get(i).getDistanceToNext();
        } else {
            distanceToNext = list.get(location).getDistanceToNext();
        }
        oxen = oxen - 2;
        if (oxen == 0) {
            OriginTrail.plr.setWagonSpeed(tempPace);
        }
        handleDate();
        EvtSpawner.instance.spawnRandomEvent();
        try {
            EvtSpawner.instance.getHandler().pop().activate();
        } catch (Exception ex) {
            Logger.getLogger(Map.class.getName()).log(Level.SEVERE, null, ex);
        }
        
    }

    /**
     * sets the date according to movement
     */
    public void handleDate() {
        OriginTrail.plr.setDay(OriginTrail.plr.getDay() + 1);
        if ((OriginTrail.plr.getDay() == 31) && ((OriginTrail.plr.getMonth() == 11) || (OriginTrail.plr.getMonth() == 9)
                || (OriginTrail.plr.getMonth() == 4) || (OriginTrail.plr.getMonth() == 6))) {
            OriginTrail.plr.setDay(1);
            OriginTrail.plr.setMonth(OriginTrail.plr.getMonth() + 1);
        } else if ((OriginTrail.plr.getDay() == 32) && ((OriginTrail.plr.getMonth() == 1) || (OriginTrail.plr.getMonth() == 2)
                || (OriginTrail.plr.getMonth() == 3) || (OriginTrail.plr.getMonth() == 5) || (OriginTrail.plr.getMonth() == 7) || (OriginTrail.plr.getMonth() == 8)
                || (OriginTrail.plr.getMonth() == 10) || (OriginTrail.plr.getMonth() == 12))) {
            OriginTrail.plr.setDay(1);
            OriginTrail.plr.setMonth(OriginTrail.plr.getMonth() + 1);
        }
        if (OriginTrail.plr.getMonth() == 13) {
            OriginTrail.plr.setMonth(1);
            OriginTrail.plr.setYear(OriginTrail.plr.getYear()+1);
        }
    }

    /**
     * @return distance between the current map node and the next map node
     */
    public int distance() {
        return list.get(location).getDistance();
    }

    /**
     * @return distanceTraveled distance traveled by player
     */
    public int distanceTraveled() {
        return distanceTraveled;
    }

    /**
     * @return distanceToNext the player is from the next node
     */
    public int getDistanceToNext() {
        return distanceToNext;
    }

    /**
     * Returns the name of the current location
     * @return list.get(location).getName()
     */
    public String getCurrentLocation() {
        return list.get(location).getName();
    }

    /**
     * Determines if the player is at the location and if it has a shop
     * @return map.hasShop
     */
    public boolean hasShop() {
        return (list.get(location).hasShop() && ((distance() - getDistanceToNext()) == 0));
    }

    /**
     * Determines if the player is at the location and if it has a river
     * @return map.hasRiver
     */
    public boolean hasRiver() {
        return (list.get(location).hasRiver() && ((distance() - getDistanceToNext()) == 0));
    }

    /**
     * Method that adds a node to the current map
     * @param e a map node to be added to the map.
     * @return true attempted add success
     */
    @Override
    public boolean add(MapNode e) {
        if (!(e.equals(null))) {
            list.add(e);
            return true;
        }
        return false;
    }

    /**
     * clears the map
     */
    @Override
    public void clear() {
        list.clear();
    }

    /**
     * 
     * @param o
     * @return false
     */
    @Override
    public boolean contains(Object o) {
        if (!(o.equals(null))) {
            return list.contains(o);
        }
        return false;
    }

    /**
     * 
     * @param index
     * @return list.get(index)
     */
    @Override
    public MapNode get(int index) {
        return list.get(index);
    }

    /**
     * 
     * @param o
     * @return list.indexOf()
     */
    @Override
    public int indexOf(Object o) {
        return list.indexOf(o);
    }

    /**
     * 
     * @return list.isEmpty()
     */
    @Override
    public boolean isEmpty() {

        return list.isEmpty();
    }

    /**
     * 
     * @param o
     * @return list.remove(o)
     */
    @Override
    public boolean remove(Object o) {
        if (!(o.equals(null))) {
            return list.remove(o);
        }
        return false;
    }

    /**
     * 
     * @param index
     * @return list.remove(index)
     */
    @Override
    public MapNode remove(int index) {

        return list.remove(index);
    }

    /**
     * 
     * @return list.size()
     */
    @Override
    public int size() {
        return list.size();
    }

    /**
     * 
     * @return list.toArray()
     */
    @Override
    public Object[] toArray() {

        return list.toArray();
    }

    public boolean isEnd() {
        return list.get(location).isEnd();
    }

    //extra stuff(for now)
    /**
     * 
     * @param fromIndex
     * @param toIndex
     * @return null
     */
    @Override
    public List<MapNode> subList(int fromIndex, int toIndex) {

        return null;
    }

    /**
     * 
     * @param index
     * @param element
     */
    @Override
    public void add(int index, MapNode element) {
    }

    /**
     * 
     * @param c
     * @return false
     */
    @Override
    public boolean addAll(Collection<? extends MapNode> c) {

        return false;
    }

    /**
     * 
     * @param index
     * @param c
     * @return false
     */
    @Override
    public boolean addAll(int index, Collection<? extends MapNode> c) {

        return false;
    }

    /**
     * 
     * @param c
     * @return false
     */
    @Override
    public boolean containsAll(Collection<?> c) {

        return false;
    }

    /**
     * 
     * @return null
     */
    @Override
    public Iterator<MapNode> iterator() {

        return null;
    }

    /**
     * 
     * @param o
     * @return 0
     */
    @Override
    public int lastIndexOf(Object o) {

        return 0;
    }

    /**
     * 
     * @return null
     */
    @Override
    public ListIterator<MapNode> listIterator() {

        return null;
    }

    /**
     * 
     * @param index
     * @return null
     */
    @Override
    public ListIterator<MapNode> listIterator(int index) {

        return null;
    }

    /**
     * 
     * @param c
     * @return false
     */
    @Override
    public boolean removeAll(Collection<?> c) {

        return false;
    }

    /**
     * 
     * @param c
     * @return false
     */
    @Override
    public boolean retainAll(Collection<?> c) {

        return false;
    }

    /**
     * 
     * @param index
     * @param element
     * @return null
     */
    @Override
    public MapNode set(int index, MapNode element) {

        return null;
    }

    /**
     * 
     * @param <T>
     * @param a
     * @return null
     */
    @Override
    public <T> T[] toArray(T[] a) {
        return null;
    }

    public void setDistanceTraveled(int distanceTraveled) {
        this.distanceTraveled = distanceTraveled;
    }

    public void setLocation(int location) {
        this.location = location;
    }

    public void setDistanceToNext(int distanceToNext) {
        this.distanceToNext = distanceToNext;
    }
}
